URPを勉強している中で Blit の入力テクスチャは _MainTex で取得できることがわかったのでメモ
準備
Create > Rendering > URP Renderer Feature で Assets直下にでもCustomRendererFeatureを作成
合わせてShaderファイルも作成
URP Renderer Feature
- SerializeField で Shader を指定
- 画面と同じ大きさのRenderTextureを作成
- 緑色に塗りつぶす
- Blitコマンドで2のRenderTextureを画面に書き出す。この時Shaderを指定する
- _MainTexで2のRenderTextureが取れることを確認する
上記を確認するRenderFeatureのコードは以下
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class CustomRenderPassFeature : ScriptableRendererFeature
{
class CustomRenderPass : ScriptableRenderPass
{
private Material _material;
readonly RenderTargetHandle _testTargetHandle;
private RenderTargetIdentifier _source;
public CustomRenderPass(Material material)
{
_material = material;
_testTargetHandle.Init("_TestTexture");
}
public void Setup(RenderTargetIdentifier source)
{
_source = source;
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
var w = cameraTextureDescriptor.width;
var h = cameraTextureDescriptor.height;
// 画面と同じ大きさのRenderTextureを作成
var targetDescripter = new RenderTextureDescriptor(w, h, RenderTextureFormat.ARGB32, 0, 0);
cmd.GetTemporaryRT(_testTargetHandle.id, targetDescripter, FilterMode.Point);
// 緑色に塗りつぶし
ConfigureTarget(_testTargetHandle.id);
ConfigureClear(ClearFlag.All, Color.green);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = CommandBufferPool.Get();
// ここの第一引数が _MainTex で取れるはず
cmd.Blit(_testTargetHandle.id, _source, _material);
// コマンドを確定する(ScriptableRenderContextのキューに入る
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void FrameCleanup(CommandBuffer cmd)
{
cmd.ReleaseTemporaryRT(_testTargetHandle.id);
}
}
[SerializeField] private Shader _shader;
CustomRenderPass _scriptablePass;
public override void Create()
{
if (_shader == null) return;
var material = CoreUtils.CreateEngineMaterial(_shader);
_scriptablePass = new CustomRenderPass(material);
_scriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingTransparents;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (_shader == null) return;
_scriptablePass.Setup(renderer.cameraColorTarget);
renderer.EnqueuePass(_scriptablePass);
}
}
やっていることは単純で Blit のときに第一引数のテクスチャがちゃんとシェーダーで取得できることを確認します
Shader "Custom/TestShader"
{
Properties
{
// Blitの第一引数が _MainTex に入るため定義する
_MainTex ("Main Tex", 2D) = "while" {}
}
SubShader
{
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex); // sampler + Texture名 でそのテクスチャのサンプリング状態を取得できる
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = IN.uv;
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
// SAMPLE_TEXTURE2D : Textureの特定の位置にあるピクセルの色を取得する
return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
}
ENDHLSL
}
}
}
Shader側は _MainTex をそのままフラグメントシェーダーで返しているだけです。
あとは RendererData に RendererFeature を設定して実行すると無事に画面が緑色になったため _MainTex で取得できることが確認できました
サンプルコード等を見ていると 「なんでこのURPのコードが動いてるんだろう?」 と疑問に思うことが多く、一つ一つ解決していかないとわからないことが多いですね..